home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fritz: All Fritz
/
All Fritz.zip
/
All Fritz
/
FILES
/
PROGMISC
/
XLISP.LZH
/
XLISPSRC.ARC
/
XLCONT.C
< prev
next >
Wrap
Text File
|
1986-05-17
|
20KB
|
957 lines
/* xlcont - xlisp special forms */
/* Copyright (c) 1985, by David Michael Betz
All Rights Reserved
Permission is granted for unrestricted non-commercial use */
#include "xlisp.h"
/* external variables */
extern NODE *xlenv,*xlvalue;
extern NODE *s_car,*s_cdr,*s_nth,*s_get,*s_svalue,*s_splist,*s_aref;
extern NODE *s_lambda,*s_macro;
extern NODE *s_comma,*s_comat;
extern NODE *true;
/* forward declarations */
FORWARD NODE *bquote1();
FORWARD NODE *defun();
FORWARD NODE *let();
FORWARD NODE *prog();
FORWARD NODE *progx();
FORWARD NODE *doloop();
/* xquote - special form 'quote' */
NODE *xquote(args)
NODE *args;
{
if (atom(args))
xlfail("too few arguments");
else if (cdr(args) != NIL)
xlfail("too many arguments");
return (car(args));
}
/* xfunction - special form 'function' */
NODE *xfunction(args)
NODE *args;
{
NODE *val;
/* get the argument */
val = xlarg(&args);
xllastarg(args);
/* create a closure for lambda expressions */
if (consp(val) && car(val) == s_lambda)
val = cons(val,xlenv);
/* otherwise, get the value of a symbol */
else if (symbolp(val))
val = xlgetvalue(val);
/* otherwise, its an error */
else
xlerror("not a function",val);
/* return the function */
return (val);
}
/* xlambda - special form 'lambda' */
NODE *xlambda(args)
NODE *args;
{
NODE *fargs;
/* get the formal argument list */
fargs = xlmatch(LIST,&args);
/* create a new function definition */
return (cons(cons(s_lambda,cons(fargs,args)),xlenv));
}
/* xbquote - back quote special form */
NODE *xbquote(args)
NODE *args;
{
NODE *expr;
/* get the expression */
expr = xlarg(&args);
xllastarg(args);
/* fill in the template */
return (bquote1(expr));
}
/* bquote1 - back quote helper function */
LOCAL NODE *bquote1(expr)
NODE *expr;
{
NODE ***oldstk,*val,*list,*last,*new;
/* handle atoms */
if (atom(expr))
val = expr;
/* handle (comma <expr>) */
else if (car(expr) == s_comma) {
if (atom(cdr(expr)))
xlfail("bad comma expression");
val = xleval(car(cdr(expr)));
}
/* handle ((comma-at <expr>) ... ) */
else if (consp(car(expr)) && car(car(expr)) == s_comat) {
oldstk = xlstack;
xlstkcheck(2);
xlsave(list);
xlsave(val);
if (atom(cdr(car(expr))))
xlfail("bad comma-at expression");
list = xleval(car(cdr(car(expr))));
for (last = NIL; consp(list); list = cdr(list)) {
new = consa(car(list));
if (last)
rplacd(last,new);
else
val = new;
last = new;
}
if (last)
rplacd(last,bquote1(cdr(expr)));
else
val = bquote1(cdr(expr));
xlstack = oldstk;
}
/* handle any other list */
else {
oldstk = xlstack;
xlsave1(val);
val = consa(NIL);
rplaca(val,bquote1(car(expr)));
rplacd(val,bquote1(cdr(expr)));
xlstack = oldstk;
}
/* return the result */
return (val);
}
/* xsetq - special form 'setq' */
NODE *xsetq(args)
NODE *args;
{
NODE *sym,*val;
/* handle each pair of arguments */
for (val = NIL; args; ) {
sym = xlmatch(SYM,&args);
val = xlevarg(&args);
xlsetvalue(sym,val);
}
/* return the result value */
return (val);
}
/* xsetf - special form 'setf' */
NODE *xsetf(args)
NODE *args;
{
NODE ***oldstk,*place,*value;
/* create a new stack frame */
oldstk = xlstack;
xlsave1(value);
/* handle each pair of arguments */
while (args) {
/* get place and value */
place = xlarg(&args);
value = xlevarg(&args);
/* check the place form */
if (symbolp(place))
xlsetvalue(place,value);
else if (consp(place))
placeform(place,value);
else
xlfail("bad place form");
}
/* restore the previous stack frame */
xlstack = oldstk;
/* return the value */
return (value);
}
/* placeform - handle a place form other than a symbol */
LOCAL placeform(place,value)
NODE *place,*value;
{
NODE ***oldstk,*fun,*arg1,*arg2;
int i;
/* check the function name */
if ((fun = xlmatch(SYM,&place)) == s_get) {
oldstk = xlstack;
xlstkcheck(2);
xlsave(arg1);
xlsave(arg2);
arg1 = xlevmatch(SYM,&place);
arg2 = xlevmatch(SYM,&place);
xllastarg(place);
xlputprop(arg1,value,arg2);
xlstack = oldstk;
}
else if (fun == s_svalue) {
oldstk = xlstack;
xlsave1(arg1);
arg1 = xlevmatch(SYM,&place);
xllastarg(place);
setvalue(arg1,value);
xlstack = oldstk;
}
else if (fun == s_splist) {
oldstk = xlstack;
xlsave1(arg1);
arg1 = xlevmatch(SYM,&place);
xllastarg(place);
setplist(arg1,value);
xlstack = oldstk;
}
else if (fun == s_car) {
oldstk = xlstack;
xlsave1(arg1);
if ((arg1 = xlevmatch(LIST,&place)) == NIL)
xlerror("bad argument type",arg1);
xllastarg(place);
rplaca(arg1,value);
xlstack = oldstk;
}
else if (fun == s_cdr) {
oldstk = xlstack;
xlsave1(arg1);
if ((arg1 = xlevmatch(LIST,&place)) == NIL)
xlerror("bad argument type",arg1);
xllastarg(place);
rplacd(arg1,value);
xlstack = oldstk;
}
else if (fun == s_nth) {
oldstk = xlstack;
xlstkcheck(2);
xlsave(arg1);
xlsave(arg2);
arg1 = xlevmatch(INT,&place);
arg2 = xlevmatch(LIST,&place);
xllastarg(place);
for (i = (int)getfixnum(arg1); i > 0 && consp(arg2); --i)
arg2 = cdr(arg2);
if (consp(arg2))
rplaca(arg2,value);
xlstack = oldstk;
}
else if (fun == s_aref) {
oldstk = xlstack;
xlstkcheck(2);
xlsave(arg1);
xlsave(arg2);
arg1 = xlevmatch(VECT,&place);
arg2 = xlevmatch(INT,&place); i = (int)getfixnum(arg2);
xllastarg(place);
if (i < 0 || i >= getsize(arg1))
xlerror("index out of range",arg2);
setelement(arg1,i,value);
xlstack = oldstk;
}
else
xlfail("bad place form");
}
/* xdefun - special form 'defun' */
NODE *xdefun(args)
NODE *args;
{
return (defun(args,s_lambda));
}
/* xdefmacro - special form 'defmacro' */
NODE *xdefmacro(args)
NODE *args;
{
return (defun(args,s_macro));
}
/* defun - internal function definition routine */
LOCAL NODE *defun(args,type)
NODE *args,*type;
{
NODE *sym,*fargs;
/* get the function symbol and formal argument list */
sym = xlmatch(SYM,&args);
fargs = xlmatch(LIST,&args);
/* make the symbol point to a new function definition */
xlsetvalue(sym,cons(cons(type,cons(fargs,args)),xlenv));
/* return the function symbol */
return (sym);
}
/* xcond - special form 'cond' */
NODE *xcond(args)
NODE *args;
{
NODE *list,*val;
/* find a predicate that is true */
for (val = NIL; consp(args); args = cdr(args)) {
/* get the next conditional */
list = car(args);
/* evaluate the predicate part */
if (consp(list) && (val = xleval(car(list)))) {
/* evaluate each expression */
for (list = cdr(list); consp(list); list = cdr(list))
val = xleval(car(list));
/* exit the loop */
break;
}
}
/* return the value */
return (val);
}
/* xcase - special form 'case' */
NODE *xcase(args)
NODE *args;
{
NODE ***oldstk,*key,*list,*cases,*val;
/* create a new stack frame */
oldstk = xlstack;
xlsave1(key);
/* get the key expression */
key = xlevarg(&args);
/* find a case that matches */
for (val = NIL; consp(args); args = cdr(args)) {
/* get the next case clause */
list = car(args);
/* make sure this is a valid clause */
if (consp(list)) {
/* compare the key list against the key */
if ((cases = car(list)) == true ||
(listp(cases) && keypresent(key,cases)) ||
eql(key,cases)) {
/* evaluate each expression */
for (list = cdr(list); consp(list); list = cdr(list))
val = xleval(car(list));
/* exit the loop */
break;
}
}
else
xlerror("bad case clause",list);
}
/* restore the previous stack frame */
xlstack = oldstk;
/* return the value */
return (val);
}
/* keypresent - check for the presence of a key in a list */
LOCAL int keypresent(key,list)
NODE *key,*list;
{
for (; consp(list); list = cdr(list))
if (eql(car(list),key))
return (TRUE);
return (FALSE);
}
/* xand - special form 'and' */
NODE *xand(args)
NODE *args;
{
NODE *val;
/* evaluate each argument */
for (val = true; consp(args); args = cdr(args))
if ((val = xleval(car(args))) == NIL)
break;
/* return the result value */
return (val);
}
/* xor - special form 'or' */
NODE *xor(args)
NODE *args;
{
NODE *val;
/* evaluate each argument */
for (val = NIL; consp(args); args = cdr(args))
if ((val = xleval(car(args))))
break;
/* return the result value */
return (val);
}
/* xif - special form 'if' */
NODE *xif(args)
NODE *args;
{
NODE *testexpr,*thenexpr,*elseexpr;
/* get the test expression, then clause and else clause */
testexpr = xlarg(&args);
thenexpr = xlarg(&args);
elseexpr = (args ? xlarg(&args) : NIL);
xllastarg(args);
/* evaluate the appropriate clause */
return (xleval(xleval(testexpr) ? thenexpr : elseexpr));
}
/* xlet - special form 'let' */
NODE *xlet(args)
NODE *args;
{
return (let(args,TRUE));
}
/* xletstar - special form 'let*' */
NODE *xletstar(args)
NODE *args;
{
return (let(args,FALSE));
}
/* let - common let routine */
LOCAL NODE *let(args,pflag)
NODE *args; int pflag;
{
NODE ***oldstk,*newenv,*val;
/* create a new stack frame */
oldstk = xlstack;
xlsave1(newenv);
/* create a new environment frame */
newenv = xlframe(xlenv);
/* get the list of bindings and bind the symbols */
if (!pflag) xlenv = newenv;
dobindings(xlmatch(LIST,&args),newenv);
if (pflag) xlenv = newenv;
/* execute the code */
for (val = NIL; consp(args); args = cdr(args))
val = xleval(car(args));
/* unbind the arguments */
xlenv = cdr(xlenv);
/* restore the previous stack frame */
xlstack = oldstk;
/* return the result */
return (val);
}
/* xprog - special form 'prog' */
NODE *xprog(args)
NODE *args;
{
return (prog(args,TRUE));
}
/* xprogstar - special form 'prog*' */
NODE *xprogstar(args)
NODE *args;
{
return (prog(args,FALSE));
}
/* prog - common prog routine */
LOCAL NODE *prog(args,pflag)
NODE *args; int pflag;
{
NODE ***oldstk,*newenv,*val;
/* create a new stack frame */
oldstk = xlstack;
xlsave1(newenv);
/* create a new environment frame */
newenv = xlframe(xlenv);
/* get the list of bindings and bind the symbols */
if (!pflag) xlenv = newenv;
dobindings(xlmatch(LIST,&args),newenv);
if (pflag) xlenv = newenv;
/* execute the code */
tagblock(args,&val);
/* unbind the arguments */
xlenv = cdr(xlenv);
/* restore the previous stack frame */
xlstack = oldstk;
/* return the result */
return (val);
}
/* xgo - special form 'go' */
NODE *xgo(args)
NODE *args;
{
NODE *label;
/* get the target label */
label = xlarg(&args);
xllastarg(args);
/* transfer to the label */
xlgo(label);
}
/* xreturn - special form 'return' */
NODE *xreturn(args)
NODE *args;
{
NODE *val;
/* get the return value */
val = (args ? xlevarg(&args) : NIL);
xllastarg(args);
/* return from the inner most block */
xlreturn(val);
}
/* xprog1 - special form 'prog1' */
NODE *xprog1(args)
NODE *args;
{
return (progx(args,1));
}
/* xprog2 - special form 'prog2' */
NODE *xprog2(args)
NODE *args;
{
return (progx(args,2));
}
/* progx - common progx code */
LOCAL NODE *progx(args,n)
NODE *args; int n;
{
NODE ***oldstk,*val;
/* create a new stack frame */
oldstk = xlstack;
xlsave1(val);
/* evaluate the first n expressions */
for (; consp(args) && --n >= 0; args = cdr(args))
val = xleval(car(args));
/* evaluate each remaining argument */
for (; consp(args); args = cdr(args))
xleval(car(args));
/* restore the previous stack frame */
xlstack = oldstk;
/* return the last test expression value */
return (val);
}
/* xprogn - special form 'progn' */
NODE *xprogn(args)
NODE *args;
{
NODE *val;
/* evaluate each expression */
for (val = NIL; consp(args); args = cdr(args))
val = xleval(car(args));
/* return the last test expression value */
return (val);
}
/* xdo - special form 'do' */
NODE *xdo(args)
NODE *args;
{
return (doloop(args,TRUE));
}
/* xdostar - special form 'do*' */
NODE *xdostar(args)
NODE *args;
{
return (doloop(args,FALSE));
}
/* doloop - common do routine */
LOCAL NODE *doloop(args,pflag)
NODE *args; int pflag;
{
NODE ***oldstk,*newenv,*blist,*clist,*test,*rval;
int rbreak;
/* create a new stack frame */
oldstk = xlstack;
xlsave1(newenv);
/* get the list of bindings, the exit test and the result forms */
blist = xlmatch(LIST,&args);
clist = xlmatch(LIST,&args);
test = (consp(clist) ? car(clist) : NIL);
/* create a new environment frame */
newenv = xlframe(xlenv);
/* bind the symbols */
if (!pflag) xlenv = newenv;
dobindings(blist,newenv);
if (pflag) xlenv = newenv;
/* execute the loop as long as the test is false */
for (rbreak = FALSE; xleval(test) == NIL; doupdates(blist,pflag))
if (tagblock(args,&rval)) {
rbreak = TRUE;
break;
}
/* evaluate the result expression */
if (!rbreak && consp(clist))
for (rval = NIL, clist = cdr(clist); consp(clist); clist = cdr(clist))
rval = xleval(car(clist));
/* unbind the arguments */
xlenv = cdr(xlenv);
/* restore the previous stack frame */
xlstack = oldstk;
/* return the result */
return (rval);
}
/* xdolist - special form 'dolist' */
NODE *xdolist(args)
NODE *args;
{
NODE ***oldstk,*clist,*sym,*list,*rval;
int rbreak;
/* create a new stack frame */
oldstk = xlstack;
xlsave1(list);
/* get the control list (sym list result-expr) */
clist = xlmatch(LIST,&args);
sym = xlmatch(SYM,&clist);
list = xlevmatch(LIST,&clist);
/* initialize the local environment */
xlenv = xlframe(xlenv);
xlbind(sym,NIL,xlenv);
/* loop through the list */
for (rbreak = FALSE; consp(list); list = cdr(list)) {
/* bind the symbol to the next list element */
xlsetvalue(sym,car(list));
/* execute the loop body */
if (tagblock(args,&rval)) {
rbreak = TRUE;
break;
}
}
/* evaluate the result expression */
if (!rbreak) {
xlsetvalue(sym,NIL);
rval = (consp(clist) ? xleval(car(clist)) : NIL);
}
/* unbind the arguments */
xlenv = cdr(xlenv);
/* restore the previous stack frame */
xlstack = oldstk;
/* return the result */
return (rval);
}
/* xdotimes - special form 'dotimes' */
NODE *xdotimes(args)
NODE *args;
{
NODE *clist,*sym,*rval;
int rbreak,cnt,i;
/* get the control list (sym list result-expr) */
clist = xlmatch(LIST,&args);
sym = xlmatch(SYM,&clist);
cnt = getfixnum(xlevmatch(INT,&clist));
/* initialize the local environment */
xlenv = xlframe(xlenv);
xlbind(sym,NIL,xlenv);
/* loop through for each value from zero to cnt-1 */
for (rbreak = FALSE, i = 0; i < cnt; ++i) {
/* bind the symbol to the next list element */
xlsetvalue(sym,cvfixnum((FIXNUM)i));
/* execute the loop body */
if (tagblock(args,&rval)) {
rbreak = TRUE;
break;
}
}
/* evaluate the result expression */
if (!rbreak) {
xlsetvalue(sym,cvfixnum((FIXNUM)cnt));
rval = (consp(clist) ? xleval(car(clist)) : NIL);
}
/* unbind the arguments */
xlenv = cdr(xlenv);
/* return the result */
return (rval);
}
/* xcatch - special form 'catch' */
NODE *xcatch(args)
NODE *args;
{
NODE ***oldstk,*tag,*val;
CONTEXT cntxt;
/* create a new stack frame */
oldstk = xlstack;
xlsave1(tag);
/* get the tag */
tag = xlevarg(&args);
/* establish an execution context */
xlbegin(&cntxt,CF_THROW,tag);
/* check for 'throw' */
if (setjmp(cntxt.c_jmpbuf))
val = xlvalue;
/* otherwise, evaluate the remainder of the arguments */
else {
for (val = NIL; consp(args); args = cdr(args))
val = xleval(car(args));
}
xlend(&cntxt);
/* restore the previous stack frame */
xlstack = oldstk;
/* return the result */
return (val);
}
/* xthrow - special form 'throw' */
NODE *xthrow(args)
NODE *args;
{
NODE *tag,*val;
/* get the tag and value */
tag = xlevarg(&args);
val = (args ? xlevarg(&args) : NIL);
xllastarg(args);
/* throw the tag */
xlthrow(tag,val);
}
/* xerrset - special form 'errset' */
NODE *xerrset(args)
NODE *args;
{
NODE *expr,*flag,*val;
CONTEXT cntxt;
/* get the expression and the print flag */
expr = xlarg(&args);
flag = (args ? xlarg(&args) : true);
xllastarg(args);
/* establish an execution context */
xlbegin(&cntxt,CF_ERROR,flag);
/* check for error */
if (setjmp(cntxt.c_jmpbuf))
val = NIL;
/* otherwise, evaluate the expression */
else {
expr = xleval(expr);
val = consa(expr);
}
xlend(&cntxt);
/* return the result */
return (val);
}
/* dobindings - handle bindings for let/let*, prog/prog*, do/do* */
LOCAL dobindings(list,env)
NODE *list,*env;
{
NODE ***oldstk,*bnd,*sym,*val;
/* create a new stack frame */
oldstk = xlstack;
xlsave1(val);
/* bind each symbol in the list of bindings */
for (; consp(list); list = cdr(list)) {
/* get the next binding */
bnd = car(list);
/* handle a symbol */
if (symbolp(bnd)) {
sym = bnd;
val = NIL;
}
/* handle a list of the form (symbol expr) */
else if (consp(bnd)) {
sym = xlmatch(SYM,&bnd);
val = xlevarg(&bnd);
}
else
xlfail("bad binding");
/* bind the value to the symbol */
xlbind(sym,val,env);
}
/* restore the previous stack frame */
xlstack = oldstk;
}
/* doupdates - handle updates for do/do* */
doupdates(list,pflag)
NODE *list; int pflag;
{
NODE ***oldstk,*plist,*bnd,*sym,*val;
/* create a new stack frame */
oldstk = xlstack;
xlstkcheck(2);
xlsave(plist);
xlsave(val);
/* bind each symbol in the list of bindings */
for (; consp(list); list = cdr(list)) {
/* get the next binding */
bnd = car(list);
/* handle a list of the form (symbol expr) */
if (consp(bnd)) {
sym = xlmatch(SYM,&bnd);
bnd = cdr(bnd);
if (bnd) {
val = xlevarg(&bnd);
if (pflag)
plist = cons(cons(sym,val),plist);
else
xlsetvalue(sym,val);
}
}
}
/* set the values for parallel updates */
for (; plist; plist = cdr(plist))
xlsetvalue(car(car(plist)),cdr(car(plist)));
/* restore the previous stack frame */
xlstack = oldstk;
}
/* tagblock - execute code within a block and tagbody */
int tagblock(code,pval)
NODE *code,**pval;
{
CONTEXT cntxt;
int type,sts;
/* establish an execution context */
xlbegin(&cntxt,CF_GO|CF_RETURN,code);
/* check for a 'return' */
if ((type = setjmp(cntxt.c_jmpbuf)) == CF_RETURN) {
*pval = xlvalue;
sts = TRUE;
}
/* otherwise, enter the body */
else {
/* check for a 'go' */
if (type == CF_GO)
code = xlvalue;
/* evaluate each expression in the body */
for (; consp(code); code = cdr(code))
if (consp(car(code)))
xleval(car(code));
/* fell out the bottom of the loop */
*pval = NIL;
sts = FALSE;
}
xlend(&cntxt);
/* return status */
return (sts);
}